(self, cfg_job, current_function_addr)
Generate a CFGNode that starts at `cfg_job.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 CFGJob cfg_job: The CFGJob instance.
        :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
Generate a CFGNode that starts at `cfg_job.addr`.
Generate a CFGNode that starts at cfg_job . addr .
def _generate_cfgnode(self, cfg_job, current_function_addr):
        """
        Generate a CFGNode that starts at `cfg_job.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 CFGJob cfg_job: The CFGJob instance.
        :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
        """

        addr = cfg_job.addr

        try:

            if addr in self._nodes:
                cfg_node = self._nodes[addr]
                irsb = cfg_node.irsb

                if cfg_node.function_address != current_function_addr:
                    # the node has been assigned to another function before.
                    # we should update the function address.
                    current_function_addr = cfg_node.function_address

                return addr, current_function_addr, cfg_node, irsb

            is_x86_x64_arch = self.project.arch.name in ('X86', 'AMD64')

            if is_arm_arch(self.project.arch):
                real_addr = addr & (~1)
            else:
                real_addr = addr

            # extra check for ARM
            if is_arm_arch(self.project.arch) and self._seg_list.occupied_by_sort(addr) == "code":
                existing_node = self.get_any_node(addr, anyaddr=True)
                if existing_node is not None and (addr & 1) != (existing_node.addr & 1):
                    # we are trying to break an existing ARM node with a THUMB node, or vice versa
                    # this is probably because our current node is unexpected
                    return None, None, None, None

            distance = VEX_IRSB_MAX_SIZE
            # if there is exception handling code, check the distance between `addr` and the cloest ending address
            if self._exception_handling_by_endaddr:
                next_end = next(self._exception_handling_by_endaddr.irange(minimum=real_addr), None)
                if next_end is not None:
                    distance = min(distance, next_end - real_addr)

            # if possible, check the distance between `addr` and the end of this section
            obj = self.project.loader.find_object_containing(addr, membership_check=False)
            if obj:
                # is there a section?
                has_executable_section = self._object_has_executable_sections(obj)
                section = obj.find_section_containing(addr)
                if has_executable_section and section is None:
                    # the basic block should not exist here...
                    return None, None, None, None
                if section is not None:
                    if not section.is_executable:
                        # the section is not executable...
                        return None, None, None, None
                    distance_ = section.vaddr + section.memsize - real_addr
                    distance = min(distance_, VEX_IRSB_MAX_SIZE)
                # TODO: handle segment information as well

            # also check the distance between `addr` and the closest function.
            # we don't want to have a basic block that spans across function boundaries
            next_func = self.functions.ceiling_func(addr + 1)
            if next_func is not None:
                distance_to_func = (next_func.addr & (~1) if is_arm_arch(self.project.arch) else next_func.addr) - real_addr
                if distance_to_func != 0:
                    if distance is None:
                        distance = distance_to_func
                    else:
                        distance = min(distance, distance_to_func)

            # in the end, check the distance between `addr` and the closest occupied region in segment list
            next_noncode_addr = self._seg_list.next_pos_with_sort_not_in(addr, { "code" }, max_distance=distance)
            if next_noncode_addr is not None:
                distance_to_noncode_addr = next_noncode_addr - real_addr
                distance = min(distance, distance_to_noncode_addr)

            switch_mode_on_nodecode = False
            if is_arm_arch(self.project.arch):
                switch_mode_on_nodecode = self._arch_options.switch_mode_on_nodecode
                if real_addr in self._decoding_assumptions:
                    # we have come across this address before
                    assumption = self._decoding_assumptions[real_addr]
                    if assumption.attempted_thumb and assumption.attempted_arm:
                        # unfortunately, we have attempted both, and it couldn't be decoded as any. time to give up
                        self._seg_list.occupy(real_addr, self.project.arch.instruction_alignment, "nodecode")
                        return None, None, None, None
                    if assumption.attempted_thumb:
                        switch_mode_on_nodecode = False
                        if addr % 2 == 1 and cfg_job.job_type == CFGJob.JOB_TYPE_COMPLETE_SCANNING:
                            # we have attempted THUMB mode. time to try ARM mode instead.
                            if current_function_addr == addr:
                                current_function_addr &= ~1
                            addr &= ~1
                        else:
                            # we have attempted THUMB mode and failed to decode.
                            return None, None, None, None
                    elif assumption.attempted_arm:
                        switch_mode_on_nodecode = False
                        if addr % 2 == 0 and cfg_job.job_type == CFGJob.JOB_TYPE_COMPLETE_SCANNING:
                            # we have attempted ARM mode. time to try THUMB mode instead.
                            if current_function_addr == addr:
                                current_function_addr |= 1
                            addr |= 1
                        else:
                            # we have attempted ARM mode and failed to decode.
                            return None, None, None, None

            # Let's try to create the pyvex IRSB directly, since it's much faster
            nodecode = False
            irsb = None
            irsb_string = None
            lifted_block = None
            try:
                lifted_block = self._lift(addr, size=distance, collect_data_refs=True, strict_block_end=True,
                                          load_from_ro_regions=True)
                irsb = lifted_block.vex_nostmt
                irsb_string = lifted_block.bytes[:irsb.size]
            except SimTranslationError:
                nodecode = True

            if cfg_job.job_type == CFGJob.JOB_TYPE_COMPLETE_SCANNING:
                # special logic during the complete scanning phase

                if is_arm_arch(self.project.arch):
                    # it's way too easy to incorrectly disassemble THUMB code contains 0x4f as ARM code svc?? #????
                    # if we get a single block that getting decoded to svc?? under ARM mode, we treat it as nodecode
                    if addr % 4 == 0 and irsb.jumpkind == "Ijk_Sys_syscall":
                        if lifted_block.capstone.insns \
                                and lifted_block.capstone.insns[-1].mnemonic.startswith("svc") \
                                and lifted_block.capstone.insns[-1].operands[0].imm > 255:
                            nodecode = True

                    if (nodecode or irsb.size == 0 or irsb.jumpkind == 'Ijk_NoDecode') and switch_mode_on_nodecode:
                        # maybe the current mode is wrong?
                        nodecode = False
                        if addr % 2 == 0:
                            addr_0 = addr + 1
                        else:
                            addr_0 = addr - 1

                        if addr_0 in self._nodes:
                            # it has been analyzed before
                            cfg_node = self._nodes[addr_0]
                            irsb = cfg_node.irsb
                            return addr_0, cfg_node.function_address, cfg_node, irsb

                        try:
                            lifted_block = self._lift(addr_0, size=distance, collect_data_refs=True,
                                                      strict_block_end=True, load_from_ro_regions=True)
                            irsb = lifted_block.vex_nostmt
                            irsb_string = lifted_block.bytes[:irsb.size]
                        except SimTranslationError:
                            nodecode = True

                        if not (nodecode or irsb.size == 0 or irsb.jumpkind == 'Ijk_NoDecode'):
                            # it is decodeable
                            if current_function_addr == addr:
                                current_function_addr = addr_0
                            addr = addr_0

            is_thumb = False
            if is_arm_arch(self.project.arch) and addr % 2 == 1:
                # thumb mode
                is_thumb = True

            if is_arm_arch(self.project.arch):
                # track decoding assumptions of ARM blocks
                if cfg_job.src_node is not None:
                    src_node_realaddr = cfg_job.src_node.addr & 0xffff_fffe
                    if src_node_realaddr in self._decoding_assumptions:
                        assumption = DecodingAssumption(
                            real_addr,
                            max(irsb.size, 1) if irsb is not None else 1,
                            src_node_realaddr if cfg_job.jumpkind != "Ijk_FakeRet" else None,
                            ARMDecodingMode.THUMB if is_thumb else ARMDecodingMode.ARM)
                        self._decoding_assumptions[real_addr] = assumption
                elif cfg_job.job_type in (CFGJob.JOB_TYPE_FUNCTION_PROLOGUE, CFGJob.JOB_TYPE_COMPLETE_SCANNING):
                    # this is the source of assumptions. it might be wrong!
                    if real_addr in self._decoding_assumptions:
                        # take the existing one and update it
                        assumption = self._decoding_assumptions[real_addr]
                        if assumption.attempted_thumb and assumption.attempted_arm:
                            l.error("Unreachable reached. Please report to GitHub.")
                            return None, None, None, None

                        assumption.mode = ARMDecodingMode.THUMB if is_thumb else ARMDecodingMode.ARM
                        if is_thumb:
                            assumption.attempted_thumb = True
                        else:
                            assumption.attempted_arm = True
                    else:
                        assumption = DecodingAssumption(real_addr, max(irsb.size, 1) if irsb is not None else 1, None,
                                                        ARMDecodingMode.THUMB if is_thumb else ARMDecodingMode.ARM)
                        self._decoding_assumptions[real_addr] = assumption

            if nodecode or irsb.size == 0 or irsb.jumpkind == 'Ijk_NoDecode':
                # decoding error
                # is the current location already occupied and marked as non-code?
                # it happens in cases like the following:
                #
                #     BL a_nonreturning_func (but we don't know it does not return)
                #     alignment  (mov r8, r8)
                #  data_ref_0:
                #     DCD "type found!"
                #
                occupied_sort = self._seg_list.occupied_by_sort(real_addr)
                if occupied_sort and occupied_sort != "code":
                    # no wonder we cannot decode it
                    return None, None, None, None

                # we still occupy that location since it cannot be decoded anyways
                if irsb is None:
                    irsb_size = 0
                else:
                    irsb_size = irsb.size

                # the default case
                valid_ins = False
                nodecode_size = 1

                # special handling for ud, ud1, and ud2 on x86 and x86-64
                if irsb_string[-2:] == b'\x0f\x0b' and self.project.arch.name == 'AMD64':
                    # VEX supports ud2 and make it part of the block size, only in AMD64.
                    valid_ins = True
                    nodecode_size = 0
                elif lifted_block is not None \
                        and is_x86_x64_arch \
                        and len(lifted_block.bytes) - irsb_size > 2 \
                        and lifted_block.bytes[irsb_size : irsb_size + 2] in {
                            b'\x0f\xff',  # ud0
                            b'\x0f\xb9',  # ud1
                            b'\x0f\x0b',  # ud2
                        }:
                    # ud0, ud1, and ud2 are actually valid instructions.
                    valid_ins = True
                    # VEX does not support ud0 or ud1 or ud2 under AMD64. they are not part of the block size.
                    nodecode_size = 2
                elif is_arm_arch(self.project.arch):
                    # check for UND
                    # Ref: https://developer.arm.com/documentation/dui0489/c/arm-and-thumb-instructions/pseudo-instructions/und-pseudo-instruction
                    # load raw bytes
                    trailing = self.project.loader.memory.load((addr & 0xffff_fffe) + irsb_size, 4)
                    trailing = trailing.ljust(4, b"\x00")
                    if is_thumb:
                        if self.project.arch.instruction_endness == Endness.LE:
                            # swap endianness
                            trailing = bytes([trailing[1]]) + bytes([trailing[0]]) + \
                                       bytes([trailing[3]]) + bytes([trailing[2]])
                        if trailing[0] == 0xde:
                            # UND xx for THUMB-16
                            valid_ins = True
                            nodecode_size = 2
                        elif trailing[0] == 0xf7 and (trailing[1] & 0xf0) == 0xf0 and (trailing[2] & 0xf0) == 0xa0 and (trailing[3] & 0xf0) == 0xf0:
                            # UND xxx for THUMB-32
                            valid_ins = True
                            nodecode_size = 4
                    else:
                        if self.project.arch.instruction_endness == Endness.LE:
                            # swap endianness
                            trailing = trailing[::-1]
                        if (trailing[0] & 0xf) == 7 and (trailing[1] & 0xf0) == 0xf0 and (trailing[3] & 0xf0) == 0xf0:
                            # UND xxxx for ARM
                            valid_ins = True
                            nodecode_size = 4

                if not valid_ins:
                    l.error("Decoding error occurred at address %#x of function %#x.",
                            addr + irsb_size,
                            current_function_addr
                            )

                    if is_arm_arch(self.project.arch):
                        if real_addr in self._decoding_assumptions:
                            # remove and re-lift all previous blocks that have the same assumption
                            self._cascading_remove_lifted_blocks(real_addr)
                        else:
                            # in ARM, we do not allow half-decoded blocks
                            self._seg_list.occupy(real_addr, irsb_size + nodecode_size, 'nodecode')
                    else:
                        self._seg_list.occupy(real_addr, irsb_size, 'code')
                        self._seg_list.occupy(real_addr + irsb_size, nodecode_size, 'nodecode')

                    return None, None, None, None

                else:
                    self._seg_list.occupy(real_addr, irsb_size, 'code')
                    self._seg_list.occupy(real_addr + irsb_size, nodecode_size, 'nodecode')

            # Occupy the block in segment list
            if irsb.size > 0:
                self._seg_list.occupy(real_addr, irsb.size, "code")

            # Create a CFG node, and add it to the graph
            cfg_node = CFGNode(addr, irsb.size, self.model,
                               function_address=current_function_addr,
                               block_id=addr,
                               irsb=irsb,
                               thumb=is_thumb,
                               byte_string=irsb_string,
                               )
            if self._cfb is not None:
                self._cfb.add_obj(real_addr, lifted_block)

            self._model.add_node(addr, cfg_node)

            return addr, current_function_addr, cfg_node, irsb

        except (SimMemoryError, SimEngineError):
            return None, None, None, None
def _generate_cfgnode ( self , cfg_job , current_function_addr ) : addr = cfg_job . addr try : if addr in self . _nodes : cfg_node = self . _nodes [ addr ] irsb = cfg_node . irsb if cfg_node . function_address != current_function_addr : # the node has been assigned to another function before. # we should update the function address. current_function_addr = cfg_node . function_address return addr , current_function_addr , cfg_node , irsb is_x86_x64_arch = self . project . arch . name in ( 'X86' , 'AMD64' ) if is_arm_arch ( self . project . arch ) : real_addr = addr & ( ~ 1 ) else : real_addr = addr # extra check for ARM if is_arm_arch ( self . project . arch ) and self . _seg_list . occupied_by_sort ( addr ) == "code" : existing_node = self . get_any_node ( addr , anyaddr = True ) if existing_node is not None and ( addr & 1 ) != ( existing_node . addr & 1 ) : # we are trying to break an existing ARM node with a THUMB node, or vice versa # this is probably because our current node is unexpected return None , None , None , None distance = VEX_IRSB_MAX_SIZE # if there is exception handling code, check the distance between `addr` and the cloest ending address if self . _exception_handling_by_endaddr : next_end = next ( self . _exception_handling_by_endaddr . irange ( minimum = real_addr ) , None ) if next_end is not None : distance = min ( distance , next_end - real_addr ) # if possible, check the distance between `addr` and the end of this section obj = self . project . loader . find_object_containing ( addr , membership_check = False ) if obj : # is there a section? has_executable_section = self . _object_has_executable_sections ( obj ) section = obj . find_section_containing ( addr ) if has_executable_section and section is None : # the basic block should not exist here... return None , None , None , None if section is not None : if not section . is_executable : # the section is not executable... return None , None , None , None distance_ = section . vaddr + section . memsize - real_addr distance = min ( distance_ , VEX_IRSB_MAX_SIZE ) # TODO: handle segment information as well # also check the distance between `addr` and the closest function. # we don't want to have a basic block that spans across function boundaries next_func = self . functions . ceiling_func ( addr + 1 ) if next_func is not None : distance_to_func = ( next_func . addr & ( ~ 1 ) if is_arm_arch ( self . project . arch ) else next_func . addr ) - real_addr if distance_to_func != 0 : if distance is None : distance = distance_to_func else : distance = min ( distance , distance_to_func ) # in the end, check the distance between `addr` and the closest occupied region in segment list next_noncode_addr = self . _seg_list . next_pos_with_sort_not_in ( addr , { "code" } , max_distance = distance ) if next_noncode_addr is not None : distance_to_noncode_addr = next_noncode_addr - real_addr distance = min ( distance , distance_to_noncode_addr ) switch_mode_on_nodecode = False if is_arm_arch ( self . project . arch ) : switch_mode_on_nodecode = self . _arch_options . switch_mode_on_nodecode if real_addr in self . _decoding_assumptions : # we have come across this address before assumption = self . _decoding_assumptions [ real_addr ] if assumption . attempted_thumb and assumption . attempted_arm : # unfortunately, we have attempted both, and it couldn't be decoded as any. time to give up self . _seg_list . occupy ( real_addr , self . project . arch . instruction_alignment , "nodecode" ) return None , None , None , None if assumption . attempted_thumb : switch_mode_on_nodecode = False if addr % 2 == 1 and cfg_job . job_type == CFGJob . JOB_TYPE_COMPLETE_SCANNING : # we have attempted THUMB mode. time to try ARM mode instead. if current_function_addr == addr : current_function_addr &= ~ 1 addr &= ~ 1 else : # we have attempted THUMB mode and failed to decode. return None , None , None , None elif assumption . attempted_arm : switch_mode_on_nodecode = False if addr % 2 == 0 and cfg_job . job_type == CFGJob . JOB_TYPE_COMPLETE_SCANNING : # we have attempted ARM mode. time to try THUMB mode instead. if current_function_addr == addr : current_function_addr |= 1 addr |= 1 else : # we have attempted ARM mode and failed to decode. return None , None , None , None # Let's try to create the pyvex IRSB directly, since it's much faster nodecode = False irsb = None irsb_string = None lifted_block = None try : lifted_block = self . _lift ( addr , size = distance , collect_data_refs = True , strict_block_end = True , load_from_ro_regions = True ) irsb = lifted_block . vex_nostmt irsb_string = lifted_block . bytes [ : irsb . size ] except SimTranslationError : nodecode = True if cfg_job . job_type == CFGJob . JOB_TYPE_COMPLETE_SCANNING : # special logic during the complete scanning phase if is_arm_arch ( self . project . arch ) : # it's way too easy to incorrectly disassemble THUMB code contains 0x4f as ARM code svc?? #???? # if we get a single block that getting decoded to svc?? under ARM mode, we treat it as nodecode if addr % 4 == 0 and irsb . jumpkind == "Ijk_Sys_syscall" : if lifted_block . capstone . insns and lifted_block . capstone . insns [ - 1 ] . mnemonic . startswith ( "svc" ) and lifted_block . capstone . insns [ - 1 ] . operands [ 0 ] . imm > 255 : nodecode = True if ( nodecode or irsb . size == 0 or irsb . jumpkind == 'Ijk_NoDecode' ) and switch_mode_on_nodecode : # maybe the current mode is wrong? nodecode = False if addr % 2 == 0 : addr_0 = addr + 1 else : addr_0 = addr - 1 if addr_0 in self . _nodes : # it has been analyzed before cfg_node = self . _nodes [ addr_0 ] irsb = cfg_node . irsb return addr_0 , cfg_node . function_address , cfg_node , irsb try : lifted_block = self . _lift ( addr_0 , size = distance , collect_data_refs = True , strict_block_end = True , load_from_ro_regions = True ) irsb = lifted_block . vex_nostmt irsb_string = lifted_block . bytes [ : irsb . size ] except SimTranslationError : nodecode = True if not ( nodecode or irsb . size == 0 or irsb . jumpkind == 'Ijk_NoDecode' ) : # it is decodeable if current_function_addr == addr : current_function_addr = addr_0 addr = addr_0 is_thumb = False if is_arm_arch ( self . project . arch ) and addr % 2 == 1 : # thumb mode is_thumb = True if is_arm_arch ( self . project . arch ) : # track decoding assumptions of ARM blocks if cfg_job . src_node is not None : src_node_realaddr = cfg_job . src_node . addr & 0xffff_fffe if src_node_realaddr in self . _decoding_assumptions : assumption = DecodingAssumption ( real_addr , max ( irsb . size , 1 ) if irsb is not None else 1 , src_node_realaddr if cfg_job . jumpkind != "Ijk_FakeRet" else None , ARMDecodingMode . THUMB if is_thumb else ARMDecodingMode . ARM ) self . _decoding_assumptions [ real_addr ] = assumption elif cfg_job . job_type in ( CFGJob . JOB_TYPE_FUNCTION_PROLOGUE , CFGJob . JOB_TYPE_COMPLETE_SCANNING ) : # this is the source of assumptions. it might be wrong! if real_addr in self . _decoding_assumptions : # take the existing one and update it assumption = self . _decoding_assumptions [ real_addr ] if assumption . attempted_thumb and assumption . attempted_arm : l . error ( "Unreachable reached. Please report to GitHub." ) return None , None , None , None assumption . mode = ARMDecodingMode . THUMB if is_thumb else ARMDecodingMode . ARM if is_thumb : assumption . attempted_thumb = True else : assumption . attempted_arm = True else : assumption = DecodingAssumption ( real_addr , max ( irsb . size , 1 ) if irsb is not None else 1 , None , ARMDecodingMode . THUMB if is_thumb else ARMDecodingMode . ARM ) self . _decoding_assumptions [ real_addr ] = assumption if nodecode or irsb . size == 0 or irsb . jumpkind == 'Ijk_NoDecode' : # decoding error # is the current location already occupied and marked as non-code? # it happens in cases like the following: # #     BL a_nonreturning_func (but we don't know it does not return) #     alignment  (mov r8, r8) #  data_ref_0: #     DCD "type found!" # occupied_sort = self . _seg_list . occupied_by_sort ( real_addr ) if occupied_sort and occupied_sort != "code" : # no wonder we cannot decode it return None , None , None , None # we still occupy that location since it cannot be decoded anyways if irsb is None : irsb_size = 0 else : irsb_size = irsb . size # the default case valid_ins = False nodecode_size = 1 # special handling for ud, ud1, and ud2 on x86 and x86-64 if irsb_string [ - 2 : ] == b'\x0f\x0b' and self . project . arch . name == 'AMD64' : # VEX supports ud2 and make it part of the block size, only in AMD64. valid_ins = True nodecode_size = 0 elif lifted_block is not None and is_x86_x64_arch and len ( lifted_block . bytes ) - irsb_size > 2 and lifted_block . bytes [ irsb_size : irsb_size + 2 ] in { b'\x0f\xff' , # ud0 b'\x0f\xb9' , # ud1 b'\x0f\x0b' , # ud2 } : # ud0, ud1, and ud2 are actually valid instructions. valid_ins = True # VEX does not support ud0 or ud1 or ud2 under AMD64. they are not part of the block size. nodecode_size = 2 elif is_arm_arch ( self . project . arch ) : # check for UND # Ref: https://developer.arm.com/documentation/dui0489/c/arm-and-thumb-instructions/pseudo-instructions/und-pseudo-instruction # load raw bytes trailing = self . project . loader . memory . load ( ( addr & 0xffff_fffe ) + irsb_size , 4 ) trailing = trailing . ljust ( 4 , b"\x00" ) if is_thumb : if self . project . arch . instruction_endness == Endness . LE : # swap endianness trailing = bytes ( [ trailing [ 1 ] ] ) + bytes ( [ trailing [ 0 ] ] ) + bytes ( [ trailing [ 3 ] ] ) + bytes ( [ trailing [ 2 ] ] ) if trailing [ 0 ] == 0xde : # UND xx for THUMB-16 valid_ins = True nodecode_size = 2 elif trailing [ 0 ] == 0xf7 and ( trailing [ 1 ] & 0xf0 ) == 0xf0 and ( trailing [ 2 ] & 0xf0 ) == 0xa0 and ( trailing [ 3 ] & 0xf0 ) == 0xf0 : # UND xxx for THUMB-32 valid_ins = True nodecode_size = 4 else : if self . project . arch . instruction_endness == Endness . LE : # swap endianness trailing = trailing [ : : - 1 ] if ( trailing [ 0 ] & 0xf ) == 7 and ( trailing [ 1 ] & 0xf0 ) == 0xf0 and ( trailing [ 3 ] & 0xf0 ) == 0xf0 : # UND xxxx for ARM valid_ins = True nodecode_size = 4 if not valid_ins : l . error ( "Decoding error occurred at address %#x of function %#x." , addr + irsb_size , current_function_addr ) if is_arm_arch ( self . project . arch ) : if real_addr in self . _decoding_assumptions : # remove and re-lift all previous blocks that have the same assumption self . _cascading_remove_lifted_blocks ( real_addr ) else : # in ARM, we do not allow half-decoded blocks self . _seg_list . occupy ( real_addr , irsb_size + nodecode_size , 'nodecode' ) else : self . _seg_list . occupy ( real_addr , irsb_size , 'code' ) self . _seg_list . occupy ( real_addr + irsb_size , nodecode_size , 'nodecode' ) return None , None , None , None else : self . _seg_list . occupy ( real_addr , irsb_size , 'code' ) self . _seg_list . occupy ( real_addr + irsb_size , nodecode_size , 'nodecode' ) # Occupy the block in segment list if irsb . size > 0 : self . _seg_list . occupy ( real_addr , irsb . size , "code" ) # Create a CFG node, and add it to the graph cfg_node = CFGNode ( addr , irsb . size , self . model , function_address = current_function_addr , block_id = addr , irsb = irsb , thumb = is_thumb , byte_string = irsb_string , ) if self . _cfb is not None : self . _cfb . add_obj ( real_addr , lifted_block ) self . _model . add_node ( addr , cfg_node ) return addr , current_function_addr , cfg_node , irsb except ( SimMemoryError , SimEngineError ) : return None , None , None , None