]> granicus.if.org Git - strace/commitdiff
aarch64: workaround gcc+kernel bug
authorDmitry V. Levin <ldv@altlinux.org>
Wed, 29 Mar 2017 17:55:35 +0000 (17:55 +0000)
committerDmitry V. Levin <ldv@altlinux.org>
Wed, 29 Mar 2017 18:27:14 +0000 (18:27 +0000)
Due to a subtle gcc bug that leads to miscompiled aarch64 kernels,
the 3rd argument of sched_getattr syscall is not quite 32-bit
on aarch64 as on other architectures.  For more details see
https://sourceforge.net/p/strace/mailman/message/35721703/

* defs.h (print_abnormal_hi): New prototype.
* util.c (print_abnormal_hi): New function.
* sched.c (SYS_FUNC(sched_getattr)) [AARCH64]: Use it.
* tests/sched_xetattr.c (main) [__arm64__ || __aarch64__]: Test it.

defs.h
sched.c
tests/sched_xetattr.c
util.c

diff --git a/defs.h b/defs.h
index 793971e85d49260e0e64ae5ab8285bef2aec61fd..b2be75b9e1de0be8a4f822f496c0c3a65ede9218 100644 (file)
--- a/defs.h
+++ b/defs.h
@@ -550,6 +550,7 @@ extern void print_symbolic_mode_t(unsigned int);
 extern void print_numeric_umode_t(unsigned short);
 extern void print_numeric_long_umask(unsigned long);
 extern void print_dev_t(unsigned long long dev);
+extern void print_abnormal_hi(kernel_ulong_t);
 
 extern void
 dumpiov_in_msghdr(struct tcb *, kernel_ulong_t addr, kernel_ulong_t data_size);
diff --git a/sched.c b/sched.c
index 409fb67ac544f3c73e8b688ef08d0c513890ad46..e0ee98ea6e8acb67e59b5bb31fd4410b54a87b57 100644 (file)
--- a/sched.c
+++ b/sched.c
@@ -176,7 +176,19 @@ SYS_FUNC(sched_getattr)
                        print_sched_attr(tcp, tcp->u_arg[1], size);
                else
                        printaddr(tcp->u_arg[1]);
-               tprintf(", %u, %u", size, (unsigned int) tcp->u_arg[3]);
+               tprints(", ");
+#ifdef AARCH64
+               /*
+                * Due to a subtle gcc bug that leads to miscompiled aarch64
+                * kernels, the 3rd argument of sched_getattr is not quite 32-bit
+                * as on other architectures.  For more details see
+                * https://sourceforge.net/p/strace/mailman/message/35721703/
+                */
+               if (syserror(tcp))
+                       print_abnormal_hi(tcp->u_arg[2]);
+#endif
+               tprintf("%u", size);
+               tprintf(", %u", (unsigned int) tcp->u_arg[3]);
        }
 
        return 0;
index 4b381d25c3d8fb5e4243fd3eeee7980502539785..a9bd2baa699a6447aa7dcc90a0f9b232b952eb8d 100644 (file)
@@ -81,8 +81,14 @@ main(void)
        printf("sched_getattr(%d, NULL, 0, 0) = %s\n", (int) bogus_pid, errstr);
 
        sys_sched_getattr(-1U, (unsigned long) attr, bogus_size, bogus_flags);
-       printf("sched_getattr(-1, %p, %u, %u) = %s\n",
-              attr, (unsigned) bogus_size, (unsigned) bogus_flags, errstr);
+       printf("sched_getattr(-1, %p, %s%u, %u) = %s\n",
+              attr,
+# if defined __arm64__ || defined __aarch64__
+              "0xdefaced<<32|",
+# else
+              "",
+# endif
+              (unsigned) bogus_size, (unsigned) bogus_flags, errstr);
 
        sys_sched_getattr(0, (unsigned long) efault, sizeof(*attr), 0);
        printf("sched_getattr(0, %p, %u, 0) = %s\n",
@@ -103,20 +109,31 @@ main(void)
               attr->sched_period,
               (unsigned) sizeof(*attr));
 
+# if defined __arm64__ || defined __aarch64__
+       long rc =
+# endif
        sys_sched_getattr(F8ILL_KULONG_MASK, (unsigned long) attr,
                          F8ILL_KULONG_MASK | sizeof(*attr), F8ILL_KULONG_MASK);
-       printf("sched_getattr(0, {size=%u, sched_policy=", attr->size);
-       printxval(schedulers, attr->sched_policy, NULL);
-       printf(", sched_flags=%s, sched_nice=%d, sched_priority=%u"
-              ", sched_runtime=%" PRIu64 ", sched_deadline=%" PRIu64
-              ", sched_period=%" PRIu64 "}, %u, 0) = 0\n",
-              attr->sched_flags ? "SCHED_FLAG_RESET_ON_FORK" : "0",
-              attr->sched_nice,
-              attr->sched_priority,
-              attr->sched_runtime,
-              attr->sched_deadline,
-              attr->sched_period,
-              (unsigned) sizeof(*attr));
+# if defined __arm64__ || defined __aarch64__
+       if (rc) {
+               printf("sched_getattr(0, %p, 0xffffffff<<32|%u, 0) = %s\n",
+                      attr, (unsigned) sizeof(*attr), errstr);
+       } else
+# endif
+       {
+               printf("sched_getattr(0, {size=%u, sched_policy=", attr->size);
+               printxval(schedulers, attr->sched_policy, NULL);
+               printf(", sched_flags=%s, sched_nice=%d, sched_priority=%u"
+                      ", sched_runtime=%" PRIu64 ", sched_deadline=%" PRIu64
+                      ", sched_period=%" PRIu64 "}, %u, 0) = 0\n",
+                      attr->sched_flags ? "SCHED_FLAG_RESET_ON_FORK" : "0",
+                      attr->sched_nice,
+                      attr->sched_priority,
+                      attr->sched_runtime,
+                      attr->sched_deadline,
+                      attr->sched_period,
+                      (unsigned) sizeof(*attr));
+       }
 
        sys_sched_setattr(bogus_pid, 0, 0);
        printf("sched_setattr(%d, NULL, 0) = %s\n", (int) bogus_pid, errstr);
diff --git a/util.c b/util.c
index f05d4efdd3ee4990c65e29cbf7810acad7bfdec4..9144efb6368e0fd3902db490749443b3a6e11f3f 100644 (file)
--- a/util.c
+++ b/util.c
@@ -1535,6 +1535,17 @@ printargs_d(struct tcb *tcp)
        return RVAL_DECODED;
 }
 
+/* Print abnormal high bits of a kernel_ulong_t value. */
+void
+print_abnormal_hi(const kernel_ulong_t val)
+{
+       if (current_klongsize > 4) {
+               const unsigned int hi = (unsigned int) ((uint64_t) val >> 32);
+               if (hi)
+                       tprintf("%#x<<32|", hi);
+       }
+}
+
 #if defined _LARGEFILE64_SOURCE && defined HAVE_OPEN64
 # define open_file open64
 #else