def parse_exceptions_directory(self, rva, size):
        """Parses exception directory

        All the code related to handling exception directories is documented in
        https://auscitte.github.io/systems%20blog/Exception-Directory-pefile#implementation-details
        """

        # "For x64 and Itanium platforms; the format is different for other platforms"
        if (
            self.FILE_HEADER.Machine != MACHINE_TYPE["IMAGE_FILE_MACHINE_AMD64"]
            and self.FILE_HEADER.Machine != MACHINE_TYPE["IMAGE_FILE_MACHINE_IA64"]
        ):
            return None

        rf = Structure(self.__RUNTIME_FUNCTION_format__)
        rf_size = rf.sizeof()
        rva2rt = {}
        rt_funcs = []
        rva2infos = {}
        for _ in range(size // rf_size):
            rf = self.__unpack_data__(
                self.__RUNTIME_FUNCTION_format__,
                self.get_data(rva, rf_size),
                file_offset=self.get_offset_from_rva(rva),
            )

            if rf is None:
                break

            ui = None

            if (rf.UnwindData & 0x1) == 0:
                # according to "Improving Automated Analysis of Windows x64 Binaries",
                # if the lowest bit is set, (UnwindData & ~0x1) should point to the
                # chained RUNTIME_FUNCTION instead of UNWIND_INFO

                if (
                    rf.UnwindData in rva2infos
                ):  # unwind info data structures can be shared among functions
                    ui = rva2infos[rf.UnwindData]
                else:
                    ui = UnwindInfo(file_offset=self.get_offset_from_rva(rf.UnwindData))
                    rva2infos[rf.UnwindData] = ui

                ws = ui.unpack_in_stages(self.get_data(rf.UnwindData, ui.sizeof()))
                if ws != None:
                    self.__warnings.append(ws)
                    break
                ws = ui.unpack_in_stages(self.get_data(rf.UnwindData, ui.sizeof()))
                if ws != None:
                    self.__warnings.append(ws)
                    break

                self.__structures__.append(ui)

            entry = ExceptionsDirEntryData(struct=rf, unwindinfo=ui)
            rt_funcs.append(entry)

            rva2rt[rf.BeginAddress] = entry
            rva += rf_size

        # each chained function entry holds a reference to the function first in chain
        for rf in rt_funcs:
            if rf.unwindinfo is None:
                # TODO: have not encountered such a binary yet;
                # in theory, (UnwindData & ~0x1) should point to the chained
                # RUNTIME_FUNCTION which could be used to locate the corresponding
                # ExceptionsDirEntryData and set_chained_function_entry()
                continue
            if not hasattr(rf.unwindinfo, "FunctionEntry"):
                continue
            if rf.unwindinfo.FunctionEntry not in rva2rt:
                self.__warnings.append(
                    f"FunctionEntry of UNWIND_INFO at {rf.struct.get_file_offset():x}"
                    " points to an entry that does not exist"
                )
                continue
            try:
                rf.unwindinfo.set_chained_function_entry(
                    rva2rt[rf.unwindinfo.FunctionEntry]
                )
            except PEFormatError as excp:
                self.__warnings.append(
                    "Failed parsing FunctionEntry of UNWIND_INFO at "
                    f"{rf.struct.get_file_offset():x}: {excp}"
                )
                continue

        return rt_funcs
Parses exception directory

        All the code related to handling exception directories is documented in
        https://auscitte.github.io/systems%20blog/Exception-Directory-pefile#implementation-details
        
pefile.py