/* * Fetch 64bit argument at position arg_no and * return the index of the next argument. */ int getllval(struct tcb *tcp, unsigned long long *val, int arg_no) { #if SIZEOF_KERNEL_LONG_T > 4 # ifndef current_klongsize if (current_klongsize < SIZEOF_KERNEL_LONG_T) { # if defined(AARCH64) || defined(POWERPC64) /* Align arg_no to the next even number. */ arg_no = (arg_no + 1) & 0xe; # endif /* AARCH64 || POWERPC64 */ *val = ULONG_LONG(tcp->u_arg[arg_no], tcp->u_arg[arg_no + 1]); arg_no += 2; } else # endif /* !current_klongsize */ { *val = tcp->u_arg[arg_no]; arg_no++; } #else /* SIZEOF_KERNEL_LONG_T == 4 */ # if defined __ARM_EABI__ \ || defined LINUX_MIPSO32 \ || defined POWERPC \ || defined XTENSA /* Align arg_no to the next even number. */ arg_no = (arg_no + 1) & 0xe; # elif defined SH /* * The SH4 ABI does allow long longs in odd-numbered registers, but * does not allow them to be split between registers and memory - and * there are only four argument registers for normal functions. As a * result, pread, for example, takes an extra padding argument before * the offset. This was changed late in the 2.4 series (around 2.4.20). */ if (arg_no == 3) arg_no++; # endif /* __ARM_EABI__ || LINUX_MIPSO32 || POWERPC || XTENSA || SH */ *val = ULONG_LONG(tcp->u_arg[arg_no], tcp->u_arg[arg_no + 1]); arg_no += 2; #endif return arg_no; }
static void decode_new_sigaction(struct tcb *const tcp, const kernel_ulong_t addr) { struct new_sigaction sa; #ifndef current_wordsize if (current_wordsize < sizeof(sa.sa_handler__)) { struct new_sigaction32 sa32; if (umove_or_printaddr(tcp, addr, &sa32)) return; memset(&sa, 0, sizeof(sa)); sa.sa_handler__ = sa32.sa_handler__; sa.sa_flags = sa32.sa_flags; #if HAVE_SA_RESTORER && defined SA_RESTORER sa.sa_restorer = sa32.sa_restorer; #endif /* Kernel treats sa_mask as an array of longs. * For 32-bit process, "long" is uint32_t, thus, for example, * 32th bit in sa_mask will end up as bit 0 in sa_mask[1]. * But for (64-bit) kernel, 32th bit in sa_mask is * 32th bit in 0th (64-bit) long! * For little-endian, it's the same. * For big-endian, we swap 32-bit words. */ sa.sa_mask[0] = ULONG_LONG(sa32.sa_mask[0], sa32.sa_mask[1]); } else #endif if (umove_or_printaddr(tcp, addr, &sa)) return; tprints("{sa_handler="); print_sa_handler(sa.sa_handler__); tprints(", sa_mask="); /* * Sigset size is in tcp->u_arg[4] (SPARC) * or in tcp->u_arg[3] (all other), * but kernel won't handle sys_rt_sigaction * with wrong sigset size (just returns EINVAL instead). * We just fetch the right size, which is NSIG_BYTES. */ tprintsigmask_val("", sa.sa_mask); tprints(", sa_flags="); printflags(sigact_flags, sa.sa_flags, "SA_???"); #if HAVE_SA_RESTORER && defined SA_RESTORER if (sa.sa_flags & SA_RESTORER) { tprints(", sa_restorer="); printaddr(sa.sa_restorer); } #endif tprints("}"); }