From: Dmitry V. Levin Date: Wed, 29 Mar 2017 17:55:35 +0000 (+0000) Subject: aarch64: workaround gcc+kernel bug X-Git-Tag: v4.17~142 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=a8d2417e97e71ae01095bee1a1e563b07f2d6b41;p=strace aarch64: workaround gcc+kernel bug 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. --- diff --git a/defs.h b/defs.h index 793971e8..b2be75b9 100644 --- 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 409fb67a..e0ee98ea 100644 --- 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; diff --git a/tests/sched_xetattr.c b/tests/sched_xetattr.c index 4b381d25..a9bd2baa 100644 --- a/tests/sched_xetattr.c +++ b/tests/sched_xetattr.c @@ -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 f05d4efd..9144efb6 100644 --- 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