diff --git a/qiling/os/posix/structs.py b/qiling/os/posix/structs.py index 71851af40..a43239ade 100644 --- a/qiling/os/posix/structs.py +++ b/qiling/os/posix/structs.py @@ -121,11 +121,12 @@ class cmsghdr(Struct): def make_iovec(archbits: int, endian: QL_ENDIAN): Struct = struct.get_aligned_struct(archbits, endian) + native_type = struct.get_native_type(archbits) class iovec(Struct): _fields_ = ( - ('iov_base', ctypes.c_uint64), - ('iov_len', ctypes.c_uint64) + ('iov_base', native_type), + ('iov_len', native_type) ) return iovec diff --git a/qiling/os/posix/syscall/uio.py b/qiling/os/posix/syscall/uio.py index 6c8e6e3d6..bed58a570 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:') +from qiling.os.posix.structs import make_iovec - 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 TYPE_CHECKING: + from qiling import Qiling - if hasattr(ql.os.fd[fd], 'write'): - ql.os.fd[fd].write(buf) - return regreturn +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. + """ + iovec = make_iovec(ql.arch.bits, ql.arch.endian) -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:') + for i in range(count): + obj = iovec.load_from(ql.mem, base + i * iovec.sizeof()) - 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 + yield (obj.iov_base, obj.iov_len) - 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) - return regreturn +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 diff --git a/qiling/profiles/linux.ql b/qiling/profiles/linux.ql index 2bfe4a096..3aae7fcd9 100644 --- a/qiling/profiles/linux.ql +++ b/qiling/profiles/linux.ql @@ -5,7 +5,7 @@ entry_point = 0x1000000 [OS64] -stack_address = 0x7ffffffde000 +stack_address = 0x7ffffffd0000 stack_size = 0x30000 load_address = 0x555555554000 interp_address = 0x7ffff7dd5000