From b8ad3ebed5a85fc5022afdbf825fae3d37cb0b97 Mon Sep 17 00:00:00 2001 From: elicn Date: Sun, 4 Feb 2024 20:03:43 +0200 Subject: [PATCH] Revamp POSIX syscalls readv / writev --- qiling/os/posix/syscall/uio.py | 85 +++++++++++++++++++++------------- 1 file changed, 52 insertions(+), 33 deletions(-) diff --git a/qiling/os/posix/syscall/uio.py b/qiling/os/posix/syscall/uio.py index 6c8e6e3d..bed58a57 100644 --- a/qiling/os/posix/syscall/uio.py +++ b/qiling/os/posix/syscall/uio.py @@ -3,42 +3,61 @@ # Cross Platform and Multi Architecture Advanced Binary Emulation Framework # -from qiling import Qiling +from __future__ import annotations +from typing import TYPE_CHECKING, Iterator, Tuple -def ql_syscall_writev(ql: Qiling, fd: int, vec: int, vlen: int): - regreturn = 0 - size_t_len = ql.arch.pointersize - iov = ql.mem.read(vec, vlen * size_t_len * 2) - ql.log.debug('writev() CONTENT:') - - for i in range(vlen): - addr = ql.unpack(iov[i * size_t_len * 2 : i * size_t_len * 2 + size_t_len]) - l = ql.unpack(iov[i * size_t_len * 2 + size_t_len : i * size_t_len * 2 + size_t_len * 2]) - regreturn += l - - buf = ql.mem.read(addr, l) - ql.log.debug(f'{bytes(buf)}') - - if hasattr(ql.os.fd[fd], 'write'): - ql.os.fd[fd].write(buf) - - return regreturn +from qiling.os.posix.structs import make_iovec -def ql_syscall_readv(ql: Qiling, fd: int, vec: int, vlen: int): - regreturn = 0 - size_t_len = ql.arch.pointersize - iov = ql.mem.read(vec, vlen * size_t_len * 2) - ql.log.debug('readv() CONTENT:') +if TYPE_CHECKING: + from qiling import Qiling - for i in range(vlen): - addr = ql.unpack(iov[i * size_t_len * 2 : i * size_t_len * 2 + size_t_len]) - l = ql.unpack(iov[i * size_t_len * 2 + size_t_len : i * size_t_len * 2 + size_t_len * 2]) - regreturn += l - if hasattr(ql.os.fd[fd], 'read'): - data = ql.os.fd[fd].read(l) - ql.log.debug(f'{data!r}') - ql.mem.write(addr, data) +def __iter_iovec_array(ql: Qiling, base: int, count: int) -> Iterator[Tuple[int, int]]: + """Iterate over an iovec array, yielding one iovec's fields at a time. + """ - return regreturn + iovec = make_iovec(ql.arch.bits, ql.arch.endian) + + for i in range(count): + obj = iovec.load_from(ql.mem, base + i * iovec.sizeof()) + + yield (obj.iov_base, obj.iov_len) + + +def ql_syscall_writev(ql: Qiling, fd: int, iov: int, iovcnt: int): + ret = 0 + + if hasattr(ql.os.fd[fd], 'write'): + ql.log.debug('writev CONTENT:') + + for iov_base, iov_len in __iter_iovec_array(ql, iov, iovcnt): + data = ql.mem.read(iov_base, iov_len) + ql.log.debug(f' {iov_base = :#x}, {iov_len = :#x} : {bytes(data)}') + + ql.os.fd[fd].write(data) + ret += len(data) + + else: + ql.log.debug('writev: destination fd is not writeable, no bytes were written') + + return ret + + +def ql_syscall_readv(ql: Qiling, fd: int, iov: int, iovcnt: int): + ret = 0 + + if hasattr(ql.os.fd[fd], 'read'): + ql.log.debug('readv CONTENT:') + + for iov_base, iov_len in __iter_iovec_array(ql, iov, iovcnt): + data = ql.os.fd[fd].read(iov_len) + ql.log.debug(f' {iov_base = :#x}, {iov_len = :#x} : {bytes(data)}') + + ql.mem.write(iov_base, data) + ret += len(data) + + else: + ql.log.debug('readv: source fd is not readable, no bytes were read') + + return ret