]> granicus.if.org Git - strace/commitdiff
Comment inner workings of sys_[l]lseek
authorDenys Vlasenko <vda.linux@googlemail.com>
Sun, 17 Feb 2013 00:38:14 +0000 (01:38 +0100)
committerDenys Vlasenko <vda.linux@googlemail.com>
Sun, 17 Feb 2013 00:38:14 +0000 (01:38 +0100)
The code doesn't look fully correct to me, but I need to experiment
on actual x32 machine before I start "fixing" things.
For now, add comments, and optimize out one tprints() call...

* file.c (sys_lseek): Rename '_whence' as 'whence'.
Merge printing of ", " into subsequent tprintf.
(sys_lseek32): Likewise.
(sys_llseek): Likewise.

Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
file.c

diff --git a/file.c b/file.c
index e7792223d696cf05e6f655f46ed0df6889105c38..c3a826b144276288a537e67681e0a72741fa8691 100644 (file)
--- 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