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.
This commit is contained in:
Дмитрий Левин 2017-03-29 17:55:35 +00:00
parent 5b7681cf05
commit a8d2417e97
4 changed files with 56 additions and 15 deletions

1
defs.h
View File

@ -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);

14
sched.c
View File

@ -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;

View 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);

11
util.c
View File

@ -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