! @brief Read program data from the elf file.

        @param addr Physical address (load address) to read from.
        @param size Number of bytes to read.
        @return Requested data or None if address is unmapped.

def read(self, addr, size):
        """! @brief Read program data from the elf file.

        @param addr Physical address (load address) to read from.
        @param size Number of bytes to read.
        @return Requested data or None if address is unmapped.
        """
        for segment in self._elf.iter_segments():
            seg_addr = segment["p_paddr"]
            seg_size = min(segment["p_memsz"], segment["p_filesz"])
            if addr >= seg_addr + seg_size:
                continue
            if addr + size <= seg_addr:
                continue
            # There is at least some overlap

            if addr >= seg_addr and addr + size <= seg_addr + seg_size:
                # Region is fully contained
                data = segment.data()
                start = addr - seg_addr
                return data[start:start + size]