diff --git a/file.c b/file.c index e7792223..c3a826b1 100644 --- a/file.c +++ b/file.c @@ -523,23 +523,28 @@ static const struct xlat whence[] = { { 0, NULL }, }; +/* Linux kernel has exactly one version of lseek: + * fs/read_write.c::SYSCALL_DEFINE3(lseek, unsigned, fd, off_t, offset, unsigned, origin) + * In kernel, off_t is always the same as (kernel's) long + * (see include/uapi/asm-generic/posix_types.h), + * which means that on x32 we need to use tcp->ext_arg[N] to get offset argument. + */ #if defined(LINUX_MIPSN32) || defined(X32) int sys_lseek(struct tcb *tcp) { long long offset; - int _whence; + int whence; if (entering(tcp)) { printfd(tcp, tcp->u_arg[0]); - tprints(", "); offset = tcp->ext_arg[1]; - _whence = tcp->u_arg[2]; - if (_whence == SEEK_SET) - tprintf("%llu, ", offset); + whence = tcp->u_arg[2]; + if (whence == SEEK_SET) + tprintf(", %llu, ", offset); else - tprintf("%lld, ", offset); - printxval(whence, _whence, "SEEK_???"); + tprintf(", %lld, ", offset); + printxval(whence, whence, "SEEK_???"); } return RVAL_LUDECIMAL; } @@ -549,18 +554,17 @@ int sys_lseek32(struct tcb *tcp) { long offset; - int _whence; + int whence; if (entering(tcp)) { printfd(tcp, tcp->u_arg[0]); - tprints(", "); offset = tcp->u_arg[1]; - _whence = tcp->u_arg[2]; - if (_whence == SEEK_SET) - tprintf("%lu, ", offset); + whence = tcp->u_arg[2]; + if (whence == SEEK_SET) + tprintf(", %lu, ", offset); else - tprintf("%ld, ", offset); - printxval(whence, _whence, "SEEK_???"); + tprintf(", %ld, ", offset); + printxval(whence, whence, "SEEK_???"); } return RVAL_UDECIMAL; } @@ -570,44 +574,50 @@ int sys_lseek(struct tcb *tcp) { off_t offset; - int _whence; + int whence; if (entering(tcp)) { printfd(tcp, tcp->u_arg[0]); - tprints(", "); offset = tcp->u_arg[1]; - _whence = tcp->u_arg[2]; - if (_whence == SEEK_SET) - tprintf("%lu, ", offset); + whence = tcp->u_arg[2]; + if (whence == SEEK_SET) + tprintf(", %lu, ", offset); else - tprintf("%ld, ", offset); - printxval(whence, _whence, "SEEK_???"); + tprintf(", %ld, ", offset); + printxval(whence, whence, "SEEK_???"); } return RVAL_UDECIMAL; } #endif +/* llseek syscall takes explicitly two ulong arguments hi, lo, + * rather than one 64-bit argument for which LONG_LONG works + * appropriate for the native byte order. + * + * See kernel's fs/read_write.c::SYSCALL_DEFINE5(llseek, ...) + * + * hi,lo are "unsigned longs" and combined exactly this way in kernel: + * ((loff_t) hi << 32) | lo + * Note that for architectures with kernel's long wider than userspace longs + * (such as x32), combining code will use *kernel's*, i.e. *wide* longs + * for hi and lo. You may need to use tcp->ext_arg[N]! + */ int sys_llseek(struct tcb *tcp) { if (entering(tcp)) { printfd(tcp, tcp->u_arg[0]); - /* - * This one call takes explicitly two 32-bit arguments hi, lo, - * rather than one 64-bit argument for which LONG_LONG works - * appropriate for the native byte order. - */ if (tcp->u_arg[4] == SEEK_SET) tprintf(", %llu, ", - ((long long int) tcp->u_arg[1]) << 32 | + ((long long) tcp->u_arg[1]) << 32 | (unsigned long long) (unsigned) tcp->u_arg[2]); else tprintf(", %lld, ", - ((long long int) tcp->u_arg[1]) << 32 | + ((long long) tcp->u_arg[1]) << 32 | (unsigned long long) (unsigned) tcp->u_arg[2]); } else { - long long int off; + long long off; if (syserror(tcp) || umove(tcp, tcp->u_arg[3], &off) < 0) tprintf("%#lx, ", tcp->u_arg[3]); else